package reflect;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * author : yeswater
 * date : 2023/7/13
 */

public class ReflectTest {
    /**
     * 获取 Class 实例的方式
     *
     * @throws ClassNotFoundException
     */
    @Test
    public void test() throws ClassNotFoundException {
        // 1. 运行时类  静态属性
        Class clazz1 = String.class;

        // 2. 运行时类对象 getClass()
        String str = new String("hello");
        Class clazz2 = str.getClass();

        // 3. 全类名 Class.forName()
        Class clazz3 = Class.forName("java.lang.String");

        // 4. 类加载器
        Class clazz4 = ClassLoader.getSystemClassLoader().loadClass("java.lang.String");

        System.out.println(clazz1.hashCode());
        System.out.println(clazz2.hashCode());
        System.out.println(clazz3.hashCode());
        System.out.println(clazz4.hashCode());
    }

    @Test
    public void test2() throws Exception {
        Class clazz = String.class;
        Object o = clazz.newInstance();
    }

    /**
     * 调用指定的方法 属性
     */
    @Test
    public void test3() throws Exception {
        // 获取 TargetObject 类的 Class 对象并且创建 TargetObject 类实例
        Class<?> targetClass = Class.forName("reflect.TargetObject");
        TargetObject targetObject = (TargetObject) targetClass.newInstance();

        // 获取 TargetObject 类中定义的所有方法
        Method[] methods = targetClass.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }

        // 获取指定方法并调用
        Method publicMethod = targetClass.getDeclaredMethod("publicMethod", String.class);
        publicMethod.invoke(targetObject, "JavaGuide");

        // 调用指定的构造器
        Constructor<?> constructor = targetClass.getDeclaredConstructor();
        constructor.setAccessible(true);
        TargetObject targetObj = (TargetObject) constructor.newInstance();

        // 获取指定参数并对参数进行修改
        Field field = targetClass.getDeclaredField("value");
        //为了对类中的参数进行修改我们取消安全检查
        field.setAccessible(true);
        field.set(targetObject, "JavaGuide");

        // 调用 private 方法
        Method privateMethod = targetClass.getDeclaredMethod("privateMethod");
        // 为了调用private方法我们取消安全检查
        privateMethod.setAccessible(true);
        privateMethod.invoke(targetObject);
    }

    // 反射的动态性 获取对象
    public <T> T getInstance(String className) throws Exception {
        Class clazz = Class.forName(className);
        Constructor constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        return (T) constructor.newInstance();
    }

    // 反射的动态性 调用方法
    public Object invoke(String className, String methodName) throws Exception {
        Class clazz = Class.forName(className);
        Constructor constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        Object obj = constructor.newInstance();

        Method method = clazz.getDeclaredMethod(methodName);
        method.setAccessible(true);
        return method.invoke(obj);
    }

}
